ES 变量可以包含两种不同类型的数据:原始值和引用值。原始值是最简单的数据,引用值是多个值构成的对象。
保存原始值的变量是按值访问的,因为操作的就是存储在变量中的实际值;保存引用值的变量是按引用访问的:在操作对象时,实际上操作的是对该对象的引用而非实际的对象本身。
引用值可以随时添加、修改和删除属性,而原始值不可以。
在通过变量把一个原始值赋值到另一个变量时,原始值会被复制到新变量的位置,两个变量完全独立,互不干扰;在把引用值从一个变量赋值给另一个变量的时候,存储在变量中的值(值为指针,指向存储在堆内存中的对象)也会被复制到新变量所在的位置,操作完成后两个变量指向同一个对象。
ES 中所有函数的参数都是按值传递的,这意味着函数外的值会被复制到函数内部的参数中(原始值参照原始值复制,引用值参照引用值复制)
function setName(obj) { obj.name = "Nicholas"; obj = new Object(); obj.name = "Greg"; console.log(obj.name); //"Grey" } let person = new Object(); setName(person); console.log(person.name); // "Nicholas"
从以上例子可以看出,当函数的参数为对象时,参数是按值传递的,即 obj = person 的引用(形参复制的是实参的一份引用),改变 obj.name,由于改变的是 person 的引用,所以 person 的 name 属性也会改变;
若 person 是按引用传递的,那么当把 obj 重写时,obj 和 person 都应自动指向 name 为 Grey 的对象;但由于是按值传递,所以 obj 的原始引用未改变,只是在函数内部重新创建了 obj 对象,作用域为函数内部,函数执行结束后就会被销毁。
综上,函数按值传参,当实参为引用值时,形参复制一份实参的引用,所以改变形参的属性会影响到实参,重写形参相当于把形参变成了一个局部的对象,函数结束后就会销毁。